承上篇 出處 , 有簡體版 , 進入後自行點選
大部分 MDN 文件都有簡中版 , 感謝網友 杯(附上他的鐵人文目錄,也有提到Node, Express, MongooseDB) 提供
使用非同步 APIs
。 JS 使用非同步 APIs 的頻率高過於同步 , 用於執行一些要等某些行為先完成再開始動作的任務 。 同步 API 是一個一個操作完畢後 , 才會開始執行下一個 , 例如下面這段 log function 是同步的 , 它們會從上到下依序印出 'First, Second'
console.log('First');
console.log('Second');
非同步則是立即執行回傳 , 上一動還沒完畢就可以執行 。 一旦操作結束 , API 會使用某個機制來進行額外的操作 。 例如下方 code 會印出 'Second, First'
, 原因是就算 setTimeout()
在第一行 , 它執行結束前第四行的 console.log()
就已經執行結束
setTimeout(function() {
console.log('First');
}, 3000);
console.log('Second');
在 Node 中使用不阻擋非同步APIs ( non-blocking asynchronous APIs
) 非常重要 , 比在瀏覽器中用還更重要 ! 因為 Node 是單線事件導向 ( single-treaded event-driven ) 的執行環境 。Single threaded
是指所有要傳到 server 的 req 同時跑在同一條線上 ( 與之相對則是多產線處理 ) , 這個模式相當有效率 , 但它同時代表如果你的函式呼叫需要長時間完成的同步 methods
, 它不只塞住現在的 req , 還有每一個 web app 正在處理的 req
有很多方式可以通知 app 非同步 API 已經跑完了 , 最常見的是當你使用非同步 API 時 , 註冊 ( register ) 一個 callback function , 這會在非同步跑完的時候被觸發 。 這也是上面那段 code 使用的方法
Tip: 如果我們有一連串相依非同步又需要依序的運作 , 用 callback 會變得很雜亂 , 因為這會導致過度巢狀 , 這個問題被稱作 callback hell
。
可以用 async module , 或 ES6
的 Promises 解決這問題
Note: Express & Node 有個慣例是用錯誤優先處理的 callbacks
( 參考資料: 你懂 JavaScript 嗎?#23 Callback 出處: Summer。桑莫。夏天 ) , 這個慣例中 , 第一個函式的值是錯的 , 後續的參數包含正確的資料 。
這個部落格解釋為什麼這個方法很有用 : The Node.js Way - Understanding Error-First Callbacks (fredkschott.com)
Hello World 範例 ( 在昨天的文 ) 裡我們定義一個 callback route handler function
解決 HTTP GET
req 指向網站根目錄 ('/')
app.get('/', function(req, res) {
res.send('Hello World!');
});
Number of other res methods , 例如 : res.json()
or res.sendFile()
JS tip: 可以任意命名參數 , 第一個參數會被當作 req , 第二個當作 res , 習慣上直接如範例命名 , 有利於我們進行辨識
Express app 物件提供定義 route handlers 的方法 , 大部分的用法都很相似 :delete()
, get()
, post()
, put()
,
checkout()
, copy()
, head()
, lock()
, merge()
, mkactivity()
, mkcol()
, move()
, m-search()
, notify()
, options()
, patch()
, purge()
, report()
, search()
, subscribe()
, trace()
, unlock()
, unsubscribe()
.
有一個很特殊的 method app.all()
, 在 res 給任何 HTTP method 時會被觸發 。
這被用在指定路徑讀取 middleware functions
時 , Express 文件裡的一個範例 : req to /secret
且無論是用哪個 HTTP verb
( 前提是要 http module 有支援 )
app.all('/secret', function(req, res, next) {
console.log('Accessing the secret section ...');
next(); // pass control to the next handler
});
路由允許 URL patterns
、 從 URL 傳遞的參數值交由 handler 。
為網站特定部分把 route handlers 一起控管 , 然後用一個常見的前綴路由 ( route-prefix
, 例如 Wiki 可能把所有相關路由放在一個檔案 , 用的 prefix 是 /wiki/
) , 這樣做會很有幫助 。
在 Express 中 , 我們使用 express.Router
object , 例如 : 可以建立一個我們自己的 wiki route module ( 放在 wiki.js ) , 然後將她 export 。 如下
// wiki.js - Wiki route module
var express = require('express');
var router = express.Router();
// Home page route
router.get('/', function(req, res) {
res.send('Wiki home page');
});
// About page route
router.get('/about', function(req, res) {
res.send('About this wiki');
});
module.exports = router;
Note: 在 Router
obj 新增 routes 就像加在 app
obj 裡面一樣 ( 應該是呼應昨天的文 )
要在我們的 Express app 檔案裡面用剛剛設定的路由 , 要進行 require()
route module ( wiki.js ) , 然後呼叫 use()
去新增 middleware handling path Router , 以下兩個 routes 就可以被取用 : /wiki/
& /wiki/about
var wiki = require('./wiki.js');
// ...
app.use('/wiki', wiki);
後續將會有更多 routes 的內容 , 還有 Router 用法 。 先上連結: Routes and controllers